﻿#region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;

    using Csla;

    using MarketPulse.BusinessLogic.Core;
    using MarketPulse.BusinessLogic.Private.Criteria;

#endregion

namespace MarketPulse.BusinessLogic.Private
{
    /// <summary>
    /// This class represents a survey that is used when a mystery shopper or exit interviewer
    /// conducts either a mystery shop or exit interview.  Surveys are stored as an XML
    /// document that represents the structure and content of the survey questions and responses.
    /// It also stores information about answers and the dependencies that other containers,
    /// questions or answers have on them.
    /// 
    /// Surveys have an id which identifies a set or family of survey revisions.  Along with a revision
    /// number this id makes it possible to uniquely identify a survey.
    /// </summary>
    [Serializable]
    [Csla.Server.ObjectFactory("MarketPulse.DataAccess.Factory.SurveyFactory, MarketPulse.DataAccess.Factory")]
    public class Survey : MarketPulseBase<Survey>
    {
        #region Member Variables

            /// <summary>
            /// The Version ID of this Survey. When used in conjunction with a SurveyGuid, this
            /// uniquely identifies a given survey document.
            /// </summary>
            public static PropertyInfo<long> mVersionIdProperty = RegisterProperty<long>(p => p.VersionID);

            /// <summary>
            /// A human readable label for this survey
            /// </summary>
            public static PropertyInfo<string> mSurveyLabelProperty = RegisterProperty<string>(p => p.SurveyLabel);

            /// <summary>
            /// The XML document that describes the survey and its dependencies. 
            /// Sadly, the property type is required to be a string because XElement is not marked
            /// [Serializable] and therefore cannot be used with the Csla framework.
            /// </summary>
            public static PropertyInfo<string> mSurveyXMLProperty = RegisterProperty<string>(p => p.SurveyXML);

            /// <summary>
            /// The date and time when the survey becomes the current Survey in use
            /// </summary>
            public static PropertyInfo<SmartDate> mEffectiveStartDateTimeProperty = RegisterProperty<SmartDate>(p => p.EffectiveStartDateTime);

            /// <summary>
            /// The date and time when the survey becomes the current Survey in use
            /// </summary>
            public static PropertyInfo<SmartDate> mEffectiveEndDateTimeProperty = RegisterProperty<SmartDate>(p => p.EffectiveEndDateTime);

            /// <summary>
            /// Flag to indicate if the Xml field has been modified
            /// </summary>
            private bool mIsXmlDirty = false;

        #endregion

        #region Constructors

        /// <summary>
            /// Default constructor is private in order to (try to) enforce construction
            /// only via the static factory methods provided.
            /// </summary>
            private Survey()
            {
            }

        #endregion

        #region Methods

            #region Factory Methods

                /// <summary>
                /// Creates a new Survey via the DataPortal client proxy
                /// </summary>
                /// <returns>The newly created survey</returns>
                public static Survey New()
                {
                    return DataPortal.Create<Survey>();
                }

                /// <summary>
                /// Gets the latest Survey version via the DataPortal client proxy 
                /// </summary>
                /// <param name="guid">The survey Guid to retrieve</param>
                /// <returns>The populated survey</returns>
                public static Survey Get(Guid guid)
                {
                    return DataPortal.Fetch<Survey>(guid);
                }

                /// <summary>
                /// Gets the specific Survey version via the DataPortal client proxy 
                /// </summary>
                /// <param name="guid">The survey Guid to retrieve</param>
                /// <param name="versionId">The survey version to retrieve</param>
                /// <returns>The populated survey</returns>
                public static Survey Get(Guid guid, long versionId)
                {
                    return DataPortal.Fetch<Survey>(new UniqueSurveyCriteria(guid, versionId));
                }

                /// <summary>
                /// Gets the latest Survey version via the DataPortal client proxy 
                /// </summary>
                /// <param name="guid">The Guid of the Survey to retrieve</param>
                /// <returns>The valid Survey object (populated or empty)</returns>
                public static Survey GetByGuid(Guid guid)
                {
                    return DataPortal.Fetch<Survey>(guid);
                }

                /// <summary>
                /// Gets the specific Survey version via the DataPortal client proxy 
                /// </summary>
                /// <param name="guid">The Guid of the Survey to retrieve</param>
                /// <param name="versionId">The VersionId of the Survey to retrieve</param>
                /// <returns>The valid Survey object (populated or empty)</returns>
                public static Survey GetByGuidAndVersionId(Guid guid, long versionId)
                {
                    return DataPortal.Fetch<Survey>(new UniqueSurveyCriteria(guid, versionId));
                }

                /// <summary>
                /// Updates the supplied Survey version via the DataPortal client proxy.
                /// Incrementing the versionId of the survey if the survey Xml itself has 
                /// been updated.
                /// </summary>
                /// <param name="survey">The survey to update</param>
                /// <returns>A new survey object that represents the survey after the update</returns>
                public static Survey Update(Survey survey)
                {
                    return DataPortal.Update<Survey>(survey);
                }


            #endregion 

        #endregion

        #region Properties


            /// <summary>
            /// The VersionId of this Survey. When used in conjunction with a SurveyGuid, this
            /// uniquely identifies a given Survey document.
            /// </summary>
            public long VersionID
            {
                get { return GetProperty(mVersionIdProperty); }
                private set { SetProperty(mVersionIdProperty, value); }
            }

            /// <summary>
            /// A human readable label for this Survey
            /// </summary>
            public string SurveyLabel
            {
                get { return GetProperty(mSurveyLabelProperty); }
                set { SetProperty(mSurveyLabelProperty, value); }
            }

            /// <summary>
            /// The XML document that describes the survey and its dependencies. 
            /// Sadly, the property type is required to be a string because XElement is not marked
            /// [Serializable] and therefore cannot be used with the Csla framework.
            /// </summary>
            public System.Xml.Linq.XElement SurveyXML
            {
                get { return System.Xml.Linq.XElement.Parse(GetProperty(mSurveyXMLProperty)); }
                set
                {
                    mIsXmlDirty = true;
                    SetProperty(mSurveyXMLProperty, value.ToString(SaveOptions.DisableFormatting));
                }
            }

            /// <summary>
            /// The date and time when the survey becomes the current Survey in use
            /// </summary>
            public SmartDate EffectiveStartDateTime
            {
                get { return GetProperty(mEffectiveStartDateTimeProperty); }
                set { SetProperty(mEffectiveStartDateTimeProperty, value); }
            }

            /// <summary>
            /// The date and time when the survey becomes the current Survey in use
            /// </summary>
            public SmartDate EffectiveEndDateTime
            {
                get { return GetProperty(mEffectiveEndDateTimeProperty); }
                set { SetProperty(mEffectiveEndDateTimeProperty, value); }
            }

            /// <summary>
            /// Flag to indicate if the Xml field has been modified
            /// </summary>
            public bool IsXmlDirty
            {
                get { return mIsXmlDirty; }
            }

        #endregion

        #region Business Rules

        /// <summary>
        /// Adds business rules associated with this Business Object
        /// </summary>
        protected override void AddBusinessRules()
        {
            BusinessRules.AddRule(new StartDateGTEndDate());

            //BusinessRules.AddRule(new Csla.Rules.CommonRules.IsInRole(Csla.Rules.AuthorizationActions.WriteProperty, IdProperty, "Administrator"));
            //BusinessRules.AddRule(new Csla.Rules.CommonRules.IsInRole(Csla.Rules.AuthorizationActions.WriteProperty, NameProperty, "Administrator"));
        }

        /// <summary>
        /// Business Rule that enforces the condition EffectiveEndDate > EffectiveStartDate
        /// </summary>
        private class StartDateGTEndDate : Csla.Rules.BusinessRule
        {
            protected override void Execute(Csla.Rules.RuleContext context)
            {
                var target = (Survey)context.Target;
                if (target.ReadProperty(mEffectiveStartDateTimeProperty) > target.ReadProperty(mEffectiveEndDateTimeProperty))
                {
                    context.AddErrorResult("Start date can't be after end date");
                }
            }
        }

        #endregion

    }
}
